/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package Service;

import Constants.Command;
import Constants.PIConstants;
import Constants.Service;
import DataManager.DbManager;
import DataManager.MySQLCommonDataProvider;
import PIServer.VMSProtocolHandler;
import Shared.GameMapObj;
import Shared.MapManager;
import Utility.CommonUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.mina.core.session.IoSession;
import Message.Message;
import java.util.Timer;
import java.util.TimerTask;
import Message.SerializerHelper;

/**
 *
 * @author hanv
 */
public class ParadiseService {

    public static Logger log = LoggerFactory.getLogger(ParadiseService.class.getName());
    public static Logger logChat = LoggerFactory.getLogger("ChatLog");
    public static Logger logGame = LoggerFactory.getLogger("GameLog");

    public ParadiseService() {
        log.info("ParadiseService initialized");

        Timer threadCheck = new Timer("AutoMover", true);
        threadCheck.schedule(new TimerTask() {

            public void run() {
                Message msg = new Message(Command.MOVE_IN_MAP, Service.PARADISE_ISLAND_SERVICE);
                SerializerHelper.writeInt(0, msg);
                SerializerHelper.writeInt(CommonUtils.random(3)+1, msg);
                SerializerHelper.writeInt(CommonUtils.random(300)+300, msg);
                SerializerHelper.writeInt(CommonUtils.random(140)+120, msg);
                ServerService.broadcastMap(0, msg, null);
            }
        }, 2*1000, 3*1000);
    }

    public void processCommand(IoSession session, int userID, String userName, Message clientMsg) {
        int actionCommand = clientMsg.getActionCommand();
        switch (actionCommand) {

            case Command.JOIN_MAP:
                joinMap(session, userID, userName, clientMsg);
                break;

            case Command.LEAVE_MAP:
                int mapID = SerializerHelper.readInt(clientMsg);
                leaveMap(session, userName, mapID, true);
                break;

            case Command.CHAT_PUBLIC:
                chatPublic(session, userID, userName, clientMsg);
                break;

            case Command.MOVE_IN_MAP:
                move(session, userID, userName, clientMsg);
                break;

            case Command.KISS:
                kiss(session, userID, userName, clientMsg);
                break;

            case Command.BEAT:
                beat(session, userID, userName, clientMsg);
                break;

            case Command.SEND_GIFT:
                sendGift(session, userID, userName, clientMsg);
                break;

            case Command.GET_MAP_TELEPORT:
                getMapTeleport(session, userID, userName, clientMsg);
                break;
        }
    }

    private void joinMap(IoSession session, int userID, String userName, Message clientMsg) {
        int mapID = SerializerHelper.readInt(clientMsg);
        int x = SerializerHelper.readInt(clientMsg);
        int y = SerializerHelper.readInt(clientMsg);
        GameMapObj gm = MapManager.getInstance().getMap(mapID);
        if (gm == null) {
            log.debug("invalid map");
            return;
        }
        if (gm.containUser(userName)) {
            log.debug("user already in map");
            return;
        }

        int curMapID = (Integer)session.getAttribute("map",-1);
        if (curMapID != -1) {
            leaveMap(session, userName, curMapID, false);
        }

        session.setAttribute("posX",x);
        session.setAttribute("posY",y);
        System.out.println("New character: "+userName+" at "+x+", "+y+" - Map: "+mapID);

        MySQLCommonDataProvider commonDataManager = DbManager.GetCommonDataManager();
        Message msg = new Message(Command.RESPONSE_JOIN_MAP, Service.PARADISE_ISLAND_SERVICE);
        synchronized (gm) {
            if (gm.isFull()) {
                SerializerHelper.writeInt(0, msg);  // full map
                session.write(msg);
            } else {
                SerializerHelper.writeInt(1, msg);  // join OK
                SerializerHelper.writeInt(gm.mapID, msg);
                SerializerHelper.writeInt(gm.getNumberOfUsers(), msg);
                for (int i=0; i<gm.getNumberOfUsers(); i++) {
                    IoSession s = VMSProtocolHandler.getSessionByUserName(gm.getUserAt(i));
                    int userId = (s != null) ? (Integer) s.getAttribute("userid") : -1;
                    int posX = (s != null) ? (Integer) s.getAttribute("posX") : -1;
                    int posY = (s != null) ? (Integer) s.getAttribute("posY") : -1;
                    CharacterObj charObj = commonDataManager.loadCharacterData(userId);
                    SerializerHelper.writeString(gm.getUserAt(i), msg);
                    SerializerHelper.writeInt(userId, msg);
                    SerializerHelper.writeInt(posX, msg);
                    SerializerHelper.writeInt(posY, msg);
                    SerializerHelper.writeByte(charObj.sex, msg);
                    SerializerHelper.writeByte(charObj.hair, msg);
                    SerializerHelper.writeByte(charObj.head, msg);
                    SerializerHelper.writeByte(charObj.eyes, msg);
                    SerializerHelper.writeByte(charObj.emotion, msg);
                    SerializerHelper.writeByte(charObj.shirt, msg);
                    SerializerHelper.writeByte(charObj.pant, msg);
                    SerializerHelper.writeByte(charObj.headItem, msg);
                    SerializerHelper.writeByte(charObj.handItem, msg);
                    SerializerHelper.writeByte(charObj.faceItem, msg);
                    SerializerHelper.writeInt(charObj.petid, msg);
                }
                session.write(msg);
                session.setAttribute("map", mapID);

                CharacterObj charObj = commonDataManager.loadCharacterData(userID);
                msg = new Message(Command.RESPONSE_JOIN_MAP, Service.PARADISE_ISLAND_SERVICE);
                SerializerHelper.writeInt(2, msg);  // new user join map
                SerializerHelper.writeInt(gm.mapID, msg);
                SerializerHelper.writeString(userName, msg);
                SerializerHelper.writeInt(userID, msg);
                SerializerHelper.writeInt(x, msg);
                SerializerHelper.writeInt(y, msg);
                SerializerHelper.writeByte(charObj.sex, msg);
                SerializerHelper.writeByte(charObj.hair, msg);
                SerializerHelper.writeByte(charObj.head, msg);
                SerializerHelper.writeByte(charObj.eyes, msg);
                SerializerHelper.writeByte(charObj.emotion, msg);
                SerializerHelper.writeByte(charObj.shirt, msg);
                SerializerHelper.writeByte(charObj.pant, msg);
                SerializerHelper.writeByte(charObj.headItem, msg);
                SerializerHelper.writeByte(charObj.handItem, msg);
                SerializerHelper.writeByte(charObj.faceItem, msg);
                SerializerHelper.writeInt(charObj.petid, msg);
                ServerService.broadcastMap(mapID, msg, userName);
                gm.addUser(userName);
            }
        }
    }

    public void leaveMap(IoSession session, String userName, int mapID, boolean selfnotify) {

        GameMapObj cr = MapManager.getInstance().getMap(mapID);
        if (cr == null) {
            log.error("NULL map");
            return;
        } else if (!cr.containUser(userName)) {
            log.error("Error: {} not in user list", userName);
            return;
        }

        log.info("{} leave map {}", userName, mapID);

        Message msg = new Message(Command.RESPONSE_LEAVE_MAP, Service.PARADISE_ISLAND_SERVICE);
        SerializerHelper.writeInt(mapID, msg);
        SerializerHelper.writeString(userName, msg);

        ServerService.broadcastMap(mapID, msg, null);
        cr.removeUser(userName);
        session.removeAttribute("map");
    }

    private void chatPublic(IoSession session, int userID, String userName, Message clientMsg) {
        String text = SerializerHelper.readString(clientMsg);
        int mapID = (Integer) session.getAttribute("map",-1);
        Message msg = new Message(Command.CHAT_PUBLIC, Service.PARADISE_ISLAND_SERVICE);
        SerializerHelper.writeInt(mapID, msg);
        SerializerHelper.writeInt(userID, msg);
        SerializerHelper.writeString(text, msg);
        ServerService.broadcastMap(mapID, msg, userName);
    }

    private void move(IoSession session, int userID, String userName, Message clientMsg) {
        int x = SerializerHelper.readInt(clientMsg);
        int y = SerializerHelper.readInt(clientMsg);

        session.setAttribute("posX",x);
        session.setAttribute("posY",y);

        int mapID = (Integer) session.getAttribute("map",-1);
        Message msg = new Message(Command.MOVE_IN_MAP, Service.PARADISE_ISLAND_SERVICE);
        SerializerHelper.writeInt(mapID, msg);
        SerializerHelper.writeInt(userID, msg);
        SerializerHelper.writeInt(x, msg);
        SerializerHelper.writeInt(y, msg);
        ServerService.broadcastMap(mapID, msg, userName);
    }

    private void kiss(IoSession session, int userID, String userName, Message clientMsg) {
        int kissedUserID = SerializerHelper.readInt(clientMsg);
        int mapID = (Integer) session.getAttribute("map",-1);

        try {
            Message msg = new Message(Command.KISS, Service.PARADISE_ISLAND_SERVICE);
            SerializerHelper.writeInt(mapID, msg);
            SerializerHelper.writeInt(userID, msg);
            SerializerHelper.writeInt(kissedUserID, msg);
            ServerService.broadcastMap(mapID, msg, userName);

//            MySQLCommonDataProvider commonDataManager = DbManager.GetCommonDataManager();
            updateUserIndex(userID, PIConstants.USER_INDEX_FRIENDLY, PIConstants.FRIENDLY_KISS_ADDED);
            updateUserIndex(kissedUserID, PIConstants.USER_INDEX_HAPPY, PIConstants.HAPPY_KISSED_ADDED);
        } catch (Exception e) {
            log.error("kiss ", e);
        }
    }

    private void beat(IoSession session, int userID, String userName, Message clientMsg) {
        int beatUserID = SerializerHelper.readInt(clientMsg);
        int mapID = (Integer) session.getAttribute("map",-1);

        try {
            //todo: check user index
            Message msg = new Message(Command.BEAT, Service.PARADISE_ISLAND_SERVICE);
            SerializerHelper.writeInt(mapID, msg);
            SerializerHelper.writeInt(userID, msg);
            SerializerHelper.writeInt(beatUserID, msg);
            ServerService.broadcastMap(mapID, msg, userName);

//            MySQLCommonDataProvider commonDataManager = DbManager.GetCommonDataManager();
            updateUserIndex(userID, PIConstants.USER_INDEX_HEALTHY, PIConstants.HEALTHY_BEAT_MINUS);
            updateUserIndex(userID, PIConstants.USER_INDEX_HOSTILITY, PIConstants.HOSTILITY_BEAT_ADDED);
            updateUserIndex(userID, PIConstants.USER_INDEX_FRIENDLY, PIConstants.FRIENDLY_BEAT_MINUS);
            updateUserIndex(beatUserID, PIConstants.USER_INDEX_HEALTHY, PIConstants.HEALTHY_BEAT_MINUS);
        } catch (Exception e) {
            log.error("beat ", e);
        }
    }

    private void sendGift(IoSession session, int userID, String userName, Message clientMsg) {
        int giftID = SerializerHelper.readInt(clientMsg);
//        String giftName = SerializerHelper.readString(clientMsg);
        int toUserID = SerializerHelper.readInt(clientMsg);

        try {
            Message msg = new Message(Command.RESPONSE_SEND_GIFT, Service.PARADISE_ISLAND_SERVICE);
            MySQLCommonDataProvider commonDataManager = DbManager.GetCommonDataManager();
            int money = commonDataManager.retrieveAccountBalance(userID);
            int price = commonDataManager.getItemCost(giftID, false);
            int unusedItemNo = commonDataManager.getUserUnusedItem(toUserID);
            int result = 0;

            if (money >= price) {
                if (unusedItemNo < PIConstants.MAX_ITEM_UNUSED) {
                    commonDataManager.setUserMoney(userID, money - price,
                            String.format(StringConstant.strBuyItem, giftID), price * -1,
                            CardConstant.PURCHASE_MONEY_TYPE, CardConstant.ITEM_SERVICE_ID, -1);
                    result = commonDataManager.addUserInventory(toUserID, giftID, PIConstants.ITEM_STATUS_UNUSED);
                } else {
                    result = 3; // full inventory
                }
            } else {
                result = 4; // not enough money
            }

            SerializerHelper.writeInt(result, msg);
            session.write(msg);

            if (result == 1) {
                IoSession s = VMSProtocolHandler.getSessionByUserID(toUserID);
                if (s != null && s.isConnected()) {
                    msg.getBuffer().setPosition(0);
                    SerializerHelper.writeInt(2, msg);
                    SerializerHelper.writeInt(giftID, msg);
//                    SerializerHelper.writeString(giftName, msg);
                    SerializerHelper.writeString(userName, msg);
                    s.write(msg);
                }
            }

            updateUserIndex(userID, PIConstants.USER_INDEX_FRIENDLY, PIConstants.FRIENDLY_GIFT_ADDED);
        } catch (Exception e) {
            log.error("send gift", e);
        }
    }

    private void getMapTeleport(IoSession session, int userID, String userName, Message clientMsg) {
        int mapID = SerializerHelper.readInt(clientMsg);
        GameMapObj gm = MapManager.getInstance().getMap((mapID/100)*100);
        int startMapID = gm.mapID;
        int numOfZones = gm.noOfZones;
        Message msg = new Message(Command.RESPONSE_GET_MAP_TELEPORT, Service.PARADISE_ISLAND_SERVICE);
        SerializerHelper.writeInt(GameMapObj.MAX_USER_IN_MAP, msg);
        SerializerHelper.writeInt(GameMapObj.MAP_USER_DIFFERENCES, msg);
        SerializerHelper.writeInt(numOfZones, msg);
        for (int i=0; i<numOfZones; i++) {
            if (i != 0) {
                gm = MapManager.getInstance().getMap(startMapID + i);
            }
            SerializerHelper.writeInt(gm.getNumberOfUsers(), msg);
        }
        session.write(msg);
    }

    public static void updateUserIndex(int userID, int index, int dif) {
        MySQLCommonDataProvider commonDataManager = DbManager.GetCommonDataManager();
        commonDataManager.updateUserIndex(userID, index, dif);
        IoSession s = VMSProtocolHandler.getSessionByUserID(userID);
        if (s != null && s.isConnected()) {
            Message msg = new Message(Command.RESPONSE_UPDATE_USER_INDEX, Service.PARADISE_ISLAND_SERVICE);
            SerializerHelper.writeInt(index, msg);
            SerializerHelper.writeInt(dif, msg);
            s.write(msg);
        }
    }
}